// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
//===------------ Evaluator.cpp
//
//             This file is part of the reactor project
//                Author: R-Core Team
//
//===---------------------------------------------------------------------===//

#include "Stack.h"
#include "util.h"
#include "Evaluator.h"
#include "Any.h"
#include "Environment.h"
#include "Reactor.h"
#include "Promise.h"
#include "Array.h"
#include "Arithmetic.h"
#include "BuiltIns.h"
#include "RModule.h"
#include "Closure.h"
#include "RCompiler.h"
#include "Debugger.h"
#include "Bindings.h"
#include "RAttributes.h"
#include "RJITCompiler.h"

#include <string.h>
#include <vector>

using namespace R;

#define NEXT_OPCODE() cs[pc++]

#define RETURN_R_CALL()													\
	returnLambda(true)
#define RETURN_R_PROMISE()											\
	returnLambda(false)

#define FATAL(...)            do { Debugger::getDebugger(this); rfatal(__VA_ARGS__); } while(0)
#define ERROR_ON(__test, ...) if(__test) FATAL(__VA_ARGS__)

void (Evaluator::*Evaluator::map[])(void) = {
#define APPLY_BC(__x, ...) 		(void (Evaluator::*)())&Evaluator::eval_ ## __x,
#include "bc.def"
	0
};


Evaluator::Evaluator(Reactor* vm) {
	MyVM = vm;
	envInfo=NULL;
	stack = new Stack();
	es = EVAL_TO_EVAL;
}

Evaluator::~Evaluator() {
	delete stack;
}

Evaluator* Evaluator::get() {
	return static_cast<Evaluator*>(MutatorThread::get());
}

AnyStack *Evaluator::getAnyStack() { return &(stack->anyStack); }

Reactor* Evaluator::vm() {
	return reinterpret_cast<Reactor*>(MyVM);
}

#define ARGIDX(__v, __d)             Any**    __v = cpool->data + cs[pc - __d]
#define ARGIMM(__v, __d)             uint64_t __v = cs[pc - __d]
#define ARGLBL(__v, __d)             uint64_t __v = cs[pc - __d]
#define ARGIFI(__v, __d)             FunInfo* __v = module->funInfos + cs[pc - __d]
#define ARGIOL(__v, __d)             void*    __v = NULL /*TODO*/

#define NBP0()
#define NBP1(__t1)                   pc += 1; ARG##__t1(v0, 1)
#define NBP2(__t1,__t2)              pc += 2; ARG##__t1(v0, 2); ARG##__t2(v1, 1)
#define NBP3(__t1,__t2,__t3)         pc += 3; ARG##__t1(v0, 3); ARG##__t2(v1, 2); ARG##__t3(v2, 1)
#define NBP4(__t1,__t2,__t3,__t4)    pc += 4; ARG##__t1(v0, 4); ARG##__t2(v1, 3); ARG##__t3(v2, 2); ARG##__t4(v3, 1)
#define BCP0()
#define BCP1(__t1)                   v0
#define BCP2(__t1, __t2)             v0, v1
#define BCP3(__t1, __t2, __t3)       v0, v1, v2
#define BCP4(__t1, __t2, __t3, __t4) v0, v1, v2, v3

#define CFDECL_CF_NOP()
#define CFDECL_CF_RET()
#define CFDECL_USE_EVALSTACK()
#define CFDECL_CF_BT(i) uint64_t res =

#define CFBR_CF_NOP()
#define CFBR_CF_RET()
#define CFBR_USE_EVALSTACK()
#define CFBR_CF_BT(i) if(res) pc = v##i

void Evaluator::execute(RModule* module, Environment *top_level){
  int bcode ;

	this->module = module;
  cs = module->cs;
  cpool = &module->cpool;
	pc = module->codeSize;
	run = true;

  envInfo = stack->envStack.push(top_level, module->entryPoint);
	Promise *p = Promise::doNew(module->entryPoint, envInfo);
	module->environment = envInfo->getAsGc(); //TODO moveme

	if(vm()->argumentsInfo.precompile && module->entryPoint->code) {
		runEvalToJITPromise(p);
		stop();
		return;
	}

	stack->anyStack.push(p);
	callLambda(envInfo, module->entryPoint);

  ddo(Debugger debugger(this));
	ddo(if(vm()->argumentsInfo.debug) debugger.prompt());

  do{
//  	printf("envIdx = %lu, envstack size = %lu\n", envIdx, stack->envStack.size());
		Assert(pc < module->codeSize, "Machine must have stop already");

    bcode = NEXT_OPCODE();
		ddo(debugger.checkBreakpoints());
		ddo(debugger.printStatusLine());

    switch(bcode){
#define APPLY_BC(__x, __p, __cf, ...)													\
			case BC_##__x: {																				\
				NB##__p;																							\
				CFDECL_##__cf eval_ ## __x (BC##__p); CFBR_##__cf;    \
			} break;
#include "bc.def"
			default:
					FATAL("Bcode %s (0x%x) not implemented", BC_NAME(bcode), bcode);
					break;
		}

#ifdef R_GCTORTURE
		vmkit::Collector::collect();
#endif
  } while(run);

	stop();
}

void Evaluator::stop(){
  rprintf("=================================");
	rprintf("=       Machine ended (OK)      =");

	Debugger debugger = Debugger(this);
  ddo(debugger.dumpTopStack(stack, true, 2));
	ddo(debugger.prompt());
	if(stack->anyStack.peek()){ // FIXME remove this if when Null will have it's proper object
		stack->anyStack.peek()->print();
		PrintNewLine();
	}
	stack->anyStack.pop();
}

Any* Evaluator::getVar(Symbol* symb, bool letInStack) {
	nyi_fatal();
}
/*
	R_VAR(Promise*, p);
	R_VAR(Any*, val);
	R_VAR(Environment*, def);
	bool has = false;
	uint64_t defIdx;

	val = env->getVar(envIdx, symb, &def, &defIdx, &has);

	rerror_on(!has, "undefined variable: %s", symb->text);

	if(val && Any::isOfType<Promise>(val)) { // Remove the val part when we'll have a Null Obj
		p = static_cast<Promise*>(val);
		if(!p->value){
			//printf("%p %p %p\n", p, p->env, p->value);
			if(!p->env){
				p = Promise::doNew(p->pc, def, defIdx);
			}
			callLambda(p->env, p->fun);

			if(!letInStack)
				val = stack->anyStack.pop();
			else
				val = stack->anyStack.peek();

			p->value = val;
			if(def)
				def->createLocalVar(defIdx, symb, val);

			env->createLocalVar(envIdx, symb, val);
		} else {
			val = p->value;
		}
	} else if(letInStack)
		stack->anyStack.push(val);

	return val;
}
*/

inline void Evaluator::saveContext(){
	stack->callStack.push(module, pc, envInfo);
}

inline void Evaluator::restoreContext(){
	//rprintf("call stack size %d", stack->callStack.size());
	ActivationRecord rec = stack->callStack.pop();
	changeContext(rec.envInfo,	rec.module, rec.pc);
}

inline void Evaluator::callLambda(EnvInfo* newEnvInfo, FunInfo *fun) {
	saveContext();
	//rprintf("call stack size %d", stack->callStack.size());
	changeContext(newEnvInfo, fun->module, fun->start);
}

inline void Evaluator::changeContext(EnvInfo* new_envInfo, RModule *new_mod, uint64_t new_pc) {
	envInfo = new_envInfo;
	pc = new_pc;
	if(module != new_mod){
		module = new_mod;
		cs = module->cs;
		cpool = &module->cpool;
	}
}

inline void Evaluator::callJITLambda(EnvInfo* new_envInfo, FunInfo *fun) {
	jit_saveContext();
	jit_changeContext(new_envInfo, fun->module);
}

inline void Evaluator::jit_saveContext(){
	stack->callStack.push(module, pc, envInfo);
}

inline void Evaluator::jit_restoreContext() {
	ActivationRecord rec = stack->callStack.pop();
	jit_changeContext(rec.envInfo, rec.module);
}

inline void Evaluator::jit_changeContext(EnvInfo* new_envInfo, RModule* mod) {
	envInfo=new_envInfo;
	if(module != mod){
		module = mod;
		cs = module->cs;
		cpool = &module->cpool;
	}
}

void Evaluator::returnLambda(bool isCall) {
	//rprintf("prepare to release");
//	Environment::doRelease(stackEnv, envIdx);
	//rprintf("restore");
	restoreContext();
	//int args_offset = isCall ? cs[pc - 1] : 0;
	//rprintf("clean");
	cleanStack(isCall);
	//rprintf("ok");
}

inline void Evaluator::cleanStack(bool isCall) {
	if(isCall) {
		int args_offset = cs[pc - 1];
		stack->anyStack.set(args_offset, stack->anyStack.peek());
		stack->anyStack.pop(args_offset);
	}
	// pop EnvInfo generated for Function Call, or pushed in GETVAR for Promise
	stack->envStack.pop();
}

inline void Evaluator::returnEvalToJITFunction(uint64_t nbArgs, Any* retVal) {
	R_PARAM(retVal);
//	Environment::doRelease(stackEnv, envIdx);
	stack->envStack.pop();
	stack->anyStack.pop(nbArgs);
	// Push result in stack
	jitddo(fflush(NULL);printf("[jit-debug] pushing return Value -> ");fflush(NULL);retVal->print();PrintNewLine();fflush(NULL);)
	stack->anyStack.push(retVal);
	jit_restoreContext();
}

inline void Evaluator::returnJITFunction(Any* retVal) {
	R_PARAM(retVal);
//	Environment::doRelease(stackEnv, envIdx);
	stack->envStack.pop();
	// Push result in stack
	jitddo(fflush(NULL);printf("[jit-debug] pushing return Value -> ");fflush(NULL);retVal->print();PrintNewLine();fflush(NULL);)
	stack->anyStack.push(retVal);
	jit_restoreContext();
}

inline void Evaluator::returnJITPromise(Promise* prom, Any* retVal) {
	R_PARAM(prom);
	R_PARAM(retVal);
	// Push result in stack
	jitddo(fflush(NULL);printf("[jit-debug] pushing return Value -> ");fflush(NULL);retVal->print();PrintNewLine();fflush(NULL);)
	stack->anyStack.push(retVal);
	jit_restoreContext();
	prom->value = retVal;
}


void Evaluator::eval_PUSHCONSTARG (Any ** p1){
	debugTraceFunction();
	jitddo(printf("[jit-debug]\tvalue pushed : "); fflush(NULL); (*p1)->print(); fflush(NULL); PrintNewLine();)
	stack->anyStack.push(*p1);
}
void Evaluator::eval_PUSHARG (){
	debugTraceFunction();
	nyi_fatal();
}
void Evaluator::eval_LDCONST (Any ** p1){
	debugTraceFunction();
	eval_PUSHCONSTARG(p1);
}

void Evaluator::eval_SETVAR (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	int localPos;
	tmp = stack->anyStack.peek();
	tmp = tmp->duplicate();

	jitddo(printf("[jit-debug] Setting var@%p: %s@%p => ", envInfo, static_cast<Symbol*>(*p1)->text, *p1);fflush(NULL); tmp->print();fflush(NULL);PrintNewLine();fflush(NULL);)

	printf(">>>>>>>>> Writing: %s = %p at [%d]\n", static_cast<Symbol*>(*p1)->text, tmp, (int64_t)module->pic[pc - 2]);
	envInfo->writeAt((int64_t)module->pic[pc - 2], static_cast<Symbol*>(*p1), tmp);
	printf("%p: %p\n", envInfo->getAsGc(), envInfo->getAsGc()->content[(int64_t)module->pic[pc - 2]]);
	// envInfo->setOrCreateLocalVar(static_cast<Symbol*>(*p1), tmp);
}

void Evaluator::eval_SETVAR2 (Any** p1){
	R_VAR(Any *, tmp);
	R_VAL(Symbol *, sym, static_cast<Symbol*>(*p1));
	tmp = stack->anyStack.peek();
	tmp = tmp->duplicate();

	int hops = (int64_t)module->pic[pc - 1];
	if(hops == 0)
		envInfo->writeAt(-1, sym, tmp);
	else
		envInfo->writeAt(hops, (int64_t) module->pic[pc - 2], sym, tmp);
}

void Evaluator::eval_GETVAR_MISSOK (Any** p1){
	debugTraceFunction();
	eval_GETVAR(p1);
}

void Evaluator::eval_MKPROM (FunInfo *fi){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = Promise::doNew(fi, envInfo);
	jitddo(printf("[jit-debug] Made Promise@%p:\n[jit-debug]\tFunInfo : id=%d, module=%lu\n", tmp, fi->id, fi->module->moduleId);)
	stack->anyStack.push(tmp);
}

void Evaluator::eval_MKCLOSURE (FunInfo *funInfo){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = Closure::doNew(funInfo, envInfo->getAsGc());
	jitddo(printf("[jit-debug] Made Closure@%p:\n[jit-debug]\tFunInfo : id=%d, module=%lu\n", tmp, funInfo->id, funInfo->module->moduleId);)
	stack->anyStack.push(tmp);
}


void Evaluator::JITStackFinalize() {
	// No OP, Debug code can be inserted for JIT.
}

void Evaluator::runJITToJITPromise(Promise* prom) {
	R_PARAM(prom);
	FunInfo* info = prom->fun;
	R_VAR(Any*, retVal);

	es++;
	callJITLambda(prom->envInfo, info);
	jitddo(fflush(NULL);rprintf("Start running JIT to JIT promise '%s'", info->jitFun->getName().data());)
	retVal = info->code();
	jitddo(rprintf("JIT promise %s evaluated successfully", info->jitFun->getName().data());fflush(NULL);)

	returnJITPromise(prom, retVal);
	es--;
}

void Evaluator::runEvalToJITPromise(Promise* prom) {
	R_PARAM(prom);
	FunInfo* info = prom->fun;
	R_VAR(Any*, retVal);

	es=EVAL_TO_JIT;
	callJITLambda(prom->envInfo, info);
	ddo(rprintf("Start running EVAL to JIT promise '%s'", info->jitFun->hasName()? info->jitFun->getName().data() : "no-name");)
	retVal = info->code();
	ddo(rprintf("JIT promise %s evaluated successfully ! Returned value : ", info->jitFun->getName().data());)
	jitddo(retVal->print();PrintNewLine();)

	returnJITPromise(prom, retVal);
	es=EVAL_TO_EVAL;
}

void Evaluator::runEvalToJITFunction(Closure* val, uint64_t nbArgs, cpool_entry *pdesc) {
	R_PARAM(val);
	R_VAR(Any*, retVal);
	FunInfo* info = val->fun;
	EnvInfo* new_envInfo = 0;

	es = EVAL_TO_JIT;

	new_envInfo = stack->envStack.push(val->env, info);
	callJITLambda(new_envInfo, info);
	matchParams(nbArgs, &pdesc->data.pe_int, info, envInfo, (int32_t*)alloca(sizeof(int32_t)*nbArgs));

	ddo(rprintf("Start running EVAL to JIT function '%s' with "WORD" arg(s)", info->jitFun->getName().data(), nbArgs);)
	retVal = info->code();
	ddo(rprintf("JIT function %s executed successfully !", info->jitFun->getName().data());)

	returnEvalToJITFunction(nbArgs, retVal);
	es = EVAL_TO_EVAL;
}

void Evaluator::runJITToJITFunction(Closure* val, uint64_t nbArgs, cpool_entry *pdesc) {
	R_PARAM(val);
	R_VAR(Any*, retVal);
	FunInfo* info = val->fun;
	EnvInfo* new_envInfo = NULL;

	es++;
	new_envInfo = stack->envStack.push(val->env, info);
	callJITLambda(new_envInfo, info);
	jit_matchParams(nbArgs, &pdesc->data.pe_int, info, envInfo);

	jitddo(rprintf("Start running JIT to JIT function '%s' with "WORD" arg(s)", info->jitFun->getName().data(), nbArgs);)
	retVal = info->code();
	jitddo(rprintf("JIT function %s executed successfully !\n", info->jitFun->getName().data());)

	returnJITFunction(retVal);
	es--;
}

#define CACHE_CALLS
//#define CACHE_CALLS_NOT_USED
#if defined(CACHE_CALLS_NOT_USED) && !defined(CACHE_CALLS)
#	define CACHE_CALLS
#endif

#define GET_VAR(__val, __x, __offset) {							\
	int64_t __pos;																				\
	if((__pos = (int64_t) (module->pic[pc - __offset])) >= 0) {			\
		printf("WS>> %lld\n", __pos);\
		__val = envInfo->getVarFromWriteSet(__pos, __x);\
		printf("Get WS: %lld, %p\n", __pos, __val);			\
	} else if((__pos = (int64_t) (module->pic[pc - __offset + 1]))) {	\
		printf("RS>> %lld\n", __pos);\
		__val = envInfo->getVarFromReadSet(__pos, __x);	\
		printf("Get RS: %lld, %p\n", __pos, __val);			\
	} else {																					\
		printf("TL>> %lld", __pos);\
		__val = envInfo->getVarFromTopLevel(__x);				\
		printf("Get TL: %lld, %s, %p\n", __pos, __x->text,  __val);}		\
	}\

void Evaluator::eval_CALL (Any ** sym, uint64_t pnames, uint64_t nbArgs){
	R_VAR(Promise*, p);
	R_VAR(Any*, val);
	R_VAR(Closure*, closure);
	R_VAR(Any*, retVal);
	bool has = false;
	FunInfo *fun;

	Assert(Any::isOfType<Symbol>(*sym),
			"Need a symbol for a function call");
	GET_VAR(val, static_cast<Symbol*>(*sym), 4);
	//val = envInfo->getVar(static_cast<Symbol*>(*sym), &has, false);

	ERROR_ON(!val,
			"undefined variable: %s", static_cast<Symbol*>(*sym)->text);
	ERROR_ON(!Any::isOfType<Closure>(val),
			"Closure expected, but '%s' is not bound to a closure. This is probably a compiler bug.", static_cast<Symbol*>(*sym)->text); // FIXME this must be an assert, but I have to check the compiler before
	closure = static_cast<Closure*>(val);

	cpool_entry *pdesc = module->cpool_orig + pnames; // FIXME
	Assert(pdesc->type == CPOOL_INTSXP,
			"KW arguments description must be an int");

	fun = closure->fun;
	// Apply Force JIT option
	if(vm()->argumentsInfo.jitc && !(fun->code)) {
		RJITCompiler* jit = static_cast<RJITCompiler*>(vm()->compiler);
		jit->jitCompile(fun);
	}

	// Function has been jitted so Execute JIT.
	if(fun->code){
		runEvalToJITFunction(closure, nbArgs, pdesc);
	} else {
#ifdef CACHE_CALLS
		void **pic = &module->pic[pc - 4]; // Has to be store ``BEFORE'' CALL_R_FUNCTION
#endif
		/* This pushed env is poped in cleanStack :) */																									
		callLambda(stack->envStack.push(closure->env, fun), fun);
#ifdef CACHE_CALLS
		if(pic[3] == fun) // the good closure
			fastMatchParams(nbArgs, fun, envInfo, pic[2]);
		else {
			pic[3] = fun
#ifdef CACHE_CALLS_NOT_USED
				- 1 /* be sure to have 100% mispredictions in caches */
#endif
				;
#endif

	matchParams(nbArgs, &pdesc->data.pe_int, fun, envInfo,
#ifdef CACHE_CALLS
	(int32_t*)pic[2]);}
#else
	(int32_t*)alloca(sizeof(int32_t)*nbArgs));
#endif
	}
}

void Evaluator::jit_CALL (Any ** sym, uint64_t pnames, uint64_t nbArgs){
	R_VAR(Promise*, p);
	R_VAR(Any*, val);
	R_VAR(Any*, retVal);
	bool has = false;

	debugTraceFunction();

	Assert(Any::isOfType<Symbol>(*sym),
			"Need a symbol for a function call");
	val = envInfo->getVar(static_cast<Symbol*>(*sym), &has, false);
	rerror_on(!has,
			"undefined variable: %s", static_cast<Symbol*>(*sym)->text);
	rerror_on(!Any::isOfType<Closure>(val),
			"Closure expected, but '%s' is not bound to a closure. This is probably a compiler bug.", static_cast<Symbol*>(*sym)->text); // FIXME this must be an assert, but I have to check the compiler before

	cpool_entry *pdesc = module->cpool_orig + pnames; // FIXME
	Assert(pdesc->type == CPOOL_INTSXP,
			"KW arguments description must be an int");

	// Apply Force JIT option
	if(vm()->argumentsInfo.jitc && !(static_cast<Closure*>(val)->fun->jitFun)) {
		RJITCompiler* jit = static_cast<RJITCompiler*>(vm()->compiler);
		jit->jitCompile(static_cast<Closure*>(val)->fun);
	}

	// JIT -> JIT Call Function.
	if((static_cast<Closure*>(val)->fun->jitFun)){
		runJITToJITFunction(static_cast<Closure*>(val), nbArgs, pdesc);
	}
	// JIT -> EVAL Call Function.
	else {
		nyi_fatal();
	}
}


void Evaluator::eval_GETVAR (Any ** p1){
	R_VAR(Promise*, p);
	R_VAR(Environment*, def);
	R_VAR(Symbol*, sym);
	R_VAR(Any*, val);
	Assert(Any::isOfType<Symbol>(*p1), "GetVar on a non symbol.");
	bool has = false;
	EnvInfo* defInfo = NULL;

	sym = static_cast<Symbol*>(*p1);
	//	stack->anyStack.dump();
	printf("%s>> [%d] %lld / %lld:%lld\n", sym->text, pc, module->pic[pc - 2], ((uint64_t)module->pic[pc - 1]) >> sizeof(int), ((uint64_t)module->pic[pc - 1]) & 0xffffffff);
	
	GET_VAR(val, sym, 2);
	//val = envInfo->getVar(sym, &has, true);
	defInfo = stack->envStack.peek();

	ERROR_ON(!val, "Trying to access to '%s', which is missing", sym->text);

	if(Any::isOfType<Promise>(val)) { // Remove the val part when we'll have a Null Obj
		p = static_cast<Promise*>(val);
		val = p->value;
		if(!val) {
			FunInfo *fun = p->fun;
			//printf("%p %p %p\n", p, p->env, p->value);
			/*if(p->envInfo->isNULL()){
				p = Promise::doNew(fun, defInfo);
				defInfo->createLocalVar(sym, p);
			}
			envInfo->createLocalVar(sym, p);
			ERROR_ON(es != EVAL_TO_EVAL, "Execution state is corrupted, trying to execute EVAL code in JIT mode.");
			*/

			// Apply Force JIT option
			if(vm()->argumentsInfo.jitc && !(fun->code)) {
				RJITCompiler* jit = static_cast<RJITCompiler*>(vm()->compiler);
				jit->jitCompile(fun);
			}

			if(fun->code) {	// Call EVAL -> JIT Promise
				ddo(printf("Calling eval -> JIT Promise id = %u mod = "WORD"\n", fun->id, fun->module->moduleId);)
				runEvalToJITPromise(p);//p->env, p->fun);
			} else {						// Call EVAL -> EVAL Promise
				stack->anyStack.push(p);
				callLambda(p->envInfo, fun);
			}
		} else {
			// stack->envStack.pop(); // Pop useless def EnvInfo (pushed by getVar)
			stack->anyStack.push(val);
		}
	} else {
		//stack->envStack.pop();  // Pop useless def EnvInfo (pushed by getVar)
		stack->anyStack.push(val);
	}
}


void Evaluator::jit_GETVAR (Any ** p1){
	R_VAR(Promise*, p);
	R_VAR(Symbol*, sym);
	R_VAL(Any *, val,  *p1);
	Assert(Any::isOfType<Symbol>(val), "GetVar on a non symbol.");
	bool has = false;
	EnvInfo* defInfo=NULL;

	debugTraceFunction();

#ifdef R_GCTORTURE
	vmkit::Collector::collect();
#endif

	sym = static_cast<Symbol*>(val);
	jitddo(printf("param ( Any** p1 = %p ) -> *p1 = ", p1); sym->print(); fflush(NULL); PrintNewLine();)
	//	stack->anyStack.dump();
	val = envInfo->getVar(sym, &has, true);
	defInfo = stack->envStack.peek();

	ERROR_ON(!has, "undefined variable: %s", sym->text);
	jitddo(printf("val from env(%p)->getVar -> ", env);fflush(NULL);val->print();fflush(NULL);PrintNewLine();)
	if(val && Any::isOfType<Promise>(val)) { // Remove the val part when we'll have a Null Obj
		p = static_cast<Promise*>(val);
		val = p->value;
		if(!val){
			if(p->envInfo->isNULL()){
				p = Promise::doNew(p->fun, defInfo);
				defInfo->createLocalVar(sym, p);
			}
			envInfo->createLocalVar(sym, p);

			ERROR_ON(es < EVAL_TO_JIT, "Execution state is corrupted, trying to execute EVAL code in JIT mode.");

			// Apply Force JIT option
			if(vm()->argumentsInfo.jitc && !(p->fun->code)) {
				RJITCompiler* jit = static_cast<RJITCompiler*>(vm()->compiler);
				jit->jitCompile(p->fun);
			}

			// Call JIT -> JIT Promise
			if(p->fun->code) {
				jitddo(printf("Calling JIT -> JIT Promise id = %u mod = "WORD"\n", p->fun->id,p->fun->module->moduleId);)
				runJITToJITPromise(p);//p->env, p->fun);
			}
			// Call JIT -> EVAL Promise
			else {
				nyi_fatal();
			}
		} else {
			jitddo(printf("Promise has got value, no need to eval promise -> ");	fflush(NULL); val->print();	fflush(NULL); PrintNewLine();)
			stack->anyStack.push(val);
		}
	} else {
		jitddo(printf("Var is not a promise, value -> ");		fflush(NULL); val->print(); fflush(NULL); PrintNewLine();)
		stack->anyStack.push(val);
	}
		stack->envStack.pop(); // Pop def envInfo pushed by getVar
}

void Evaluator::eval_CHECKFUN (){
	debugTraceFunction();
	nyi_fatal();
}

void Evaluator::eval_RETURNJMP (){
	debugTraceFunction();
	RETURN_R_CALL();
}

void Evaluator::eval_RETURN (){
	R_VAR(Any *, val);
	R_VAR(Promise*, prom);
	debugTraceFunction();
	RETURN_R_PROMISE();
	val = stack->anyStack.pop();
	prom = stack->anyStack.pop<Promise>();
	stack->anyStack.push(val);
	prom->value = val;
	if(pc >= module->codeSize)
		run = false;
}

void Evaluator::eval_POP (){
	debugTraceFunction();
	stack->anyStack.pop();
}

void Evaluator::eval_VISIBLE (){
	debugTraceFunction();
	eval_POP();
}

void Evaluator::eval_INVISIBLE (){
	debugTraceFunction();
	eval_POP();
}

void Evaluator::eval_DUP (){
	debugTraceFunction();
	stack->anyStack.dup();
}

void Evaluator::eval_PRINTVALUE (){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	if(tmp)
		tmp->print();
	else
		Any::printNull();
	printf("\n");
}

uint64_t Evaluator::eval_BRIFNOT (Any ** p1, uint64_t addr){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	jitddo(
			printf("[jit-debug]\tvalue poped : ");
			fflush(NULL);
			tmp->print();
			fflush(NULL);
			PrintNewLine();)
	return !tmp->toLogicalOne();
}

uint64_t Evaluator::eval_GOTO (uint64_t addr){
	debugTraceFunction();
	return 1;
}

void Evaluator::eval_LDTRUE (){
	debugTraceFunction();
	stack->anyStack.push(ConstPool::True);
}
void Evaluator::eval_PUSHTRUEARG (){
	debugTraceFunction();
	eval_LDTRUE();
}

void Evaluator::eval_LDFALSE (){
	debugTraceFunction();
	stack->anyStack.push(ConstPool::False);
}
void Evaluator::eval_PUSHFALSEARG (){
	debugTraceFunction();
	eval_LDFALSE();
}

void Evaluator::eval_LDNULL (){
	debugTraceFunction();
	stack->anyStack.push(ConstPool::Null);
}
void Evaluator::eval_PUSHNULLARG (){
	debugTraceFunction();
	eval_LDNULL();
}

void Evaluator::eval_CALLSPECIAL (uint64_t p1, uint64_t nbArgs){
	R_VAR(Any *, tmp);
	// Let's assume that: the number or args has been checked (but how to deal with variadic)
	tmp = BuiltInMap::getEntry(p1)->callSpecial(nbArgs, stack->anyStack.asStorage(nbArgs));
	stack->anyStack.pop(nbArgs);
	stack->anyStack.push(tmp, true); // I'm not really sure it's safe to assume this, since some builtins have no args. This test should probably done in BuiltInMap::call when there is no args.
}

void Evaluator::jit_CALLSPECIAL (uint64_t p1, uint64_t nbArgs){
	R_VAR(Any *, tmp);
	// Let's assume that: the number or args has been checked (but how to deal with variadic)
	tmp = BuiltInMap::getEntry(p1)->callSpecial(nbArgs, stack->anyStack.asStorage(nbArgs));
	stack->anyStack.push(tmp, true); // I'm not really sure it's safe to assume this, since some builtins have no args. This test should probably done in BuiltInMap::call when there is no args.
}

void Evaluator::eval_CALLBUILTIN (uint64_t p1, Any ** p2, uint64_t nbArgs){
	R_VAR(Any *, tmp);
	// Let's assume that: the number or args has been checked (but how to deal with variadic)
	tmp = BuiltInMap::getEntry(p1)->callBuiltIn(nbArgs, stack->anyStack.asStorage(nbArgs));
	stack->anyStack.pop(nbArgs);
	stack->anyStack.push(tmp, true); // I'm not really sure it's safe to assume this, since some builtins have no args. This test should probably done in BuiltInMap::call when there is no args.
}

// Push and pop are made outside function in codeGenerator.
// The Evaluator's stack is used for this call. See USE_EVALSTACK macro in codeGenerator.
void Evaluator::jit_CALLBUILTIN (uint64_t p1, Any ** p2, uint64_t nbArgs){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	// Let's assume that: the number or args has been checked (but how to deal with variadic)
	tmp = BuiltInMap::getEntry(p1)->callBuiltIn(nbArgs, stack->anyStack.asStorage(nbArgs));
	stack->anyStack.push(tmp, true); // I'm not really sure it's safe to assume this, since some builtins have no args. This test should probably done in BuiltInMap::call when there is no args.
	jitddo(printf("[jit-debug] CALLBUILTIN Result -> ");fflush(NULL);tmp->print();fflush(NULL);PrintNewLine();fflush(NULL);)
}

void Evaluator::eval_STARTSUBSCRIPT (Any ** p1, uint64_t p2){debugTraceFunction();}
void Evaluator::eval_STARTSUBSET (Any ** p1, uint64_t p2){debugTraceFunction();}
void Evaluator::eval_STARTSUBASSIGN (Any ** p1, uint64_t p2){debugTraceFunction();}
void Evaluator::eval_STARTSUBASSIGN2 (Any ** p1, uint64_t p2){debugTraceFunction();}

void Evaluator::eval_DFLTSUBSCRIPT (){
	R_VAR(Any *, tmp);
	R_VAR(Any *, idx);
	debugTraceFunction();
	idx = stack->anyStack.pop();
	tmp = stack->anyStack.pop();
	ERROR_ON(!Any::isOfType<Array>(tmp),
		"Subscript is currently only for array !");

	tmp = tmp->subscript(idx);
	stack->anyStack.push(tmp, true);
}


void Evaluator::eval_DFLTSUBASSIGN2 (Any **sym){
	R_VAR(Any*, tmp);
	R_VAR(Any*, idx);
	R_VAR(Any*, vals);
	R_VAR(Any*, out_vals);
	R_VAR(Any*, res);
	debugTraceFunction();
	idx = stack->anyStack.pop();
	vals = stack->anyStack.pop();
	tmp = stack->anyStack.pop();

	out_vals = tmp->subscriptAssign(idx, vals, &res);

	if(tmp != res){
		nyi_fatal(); // FIXME need to setvar inside sym WITHOUT copy
	}

	stack->anyStack.push(out_vals, true);
}

void Evaluator::eval_DFLTSUBSET (){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	jitddo(printf("[jit-debug] DFLTSUBSET\n[jit-debug]\tvalue poped : "); fflush(NULL); tmp->print(); fflush(NULL); PrintNewLine();)
	tmp = static_cast<Any*>(stack->anyStack.pop()->subset(tmp));
	jitddo(printf("[jit-debug] RETURN VALUE ->");fflush(NULL);tmp->print();fflush(NULL);PrintNewLine();)
	stack->anyStack.push(tmp, true);
}

void Evaluator::eval_DFLTSUBASSIGN (Any **sym){
	R_VAR(Any *, tmp);
	R_VAR(Any *, vals);
	R_VAR(Any *, res);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	vals = stack->anyStack.pop();
	res = stack->anyStack.pop();
	jitddo(printf("[jit-debug] DFLTSUBASSIGN\n[jit-debug]\tvalue poped : "); fflush(NULL); tmp->print(); fflush(NULL); PrintNewLine();\
	printf("[jit-debug] DFLTSUBASSIGN\n[jit-debug]\tvalue poped : "); fflush(NULL); vals->print(); fflush(NULL); PrintNewLine();\
	printf("[jit-debug] DFLTSUBASSIGN\n[jit-debug]\tvalue poped : "); fflush(NULL); res->print(); fflush(NULL); PrintNewLine();)
	tmp = res->subsetAssign(tmp, vals); // FIXME is tmp switched with pop ?

	if(res != tmp){
		tmp->print();
		if(tmp->attributes)tmp->attributes->print();
		nyi_fatal(); // FIXME need to setvar inside sym WITHOUT copy
	}
	stack->anyStack.push(res, true);
}


void Evaluator::eval_DOLLAR (Any ** p1){
	R_VAR(Any*, value);
	R_VAR(Symbol*, symbol);
	R_VAR(Any*, res);
	debugTraceFunction();
	symbol = stack->anyStack.pop<Symbol>();
	value = stack->anyStack.pop();
	ERROR_ON(!Any::isOfType<Vector>(value),
		"'$' operator is invalid for atomic vectors");

	int idx = RAttributes::getIndexByName(value, symbol->text);
	if(idx < 0) {
		res = ConstPool::Null;
	} else {
		res = static_cast<Vector*>(value)->newInstanceWith(1, idx);
//	If we need a copy of requested element :
//		res = static_cast<Vector*>(value)->getElement(idx)->duplicate();
//		RAttributes::setNames(res, RAttributes::getNames(static_cast<Vector*>(value)->getElement(idx))->duplicate());
	}

	stack->anyStack.push(res, true);
}

void Evaluator::eval_DOLLARGETS (Any ** p1, Any ** p2){
	debugTraceFunction();
	nyi_fatal();
}

void Evaluator::eval_UMINUS (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	ERROR_ON(!Any::isOfType<Array>(tmp),
			"Unary '-' only works for array, but " WORD " found", Any::getType(tmp)); // FIXME
	tmp = static_cast<Array *>(tmp)->opposite();
	stack->anyStack.push(tmp, true);
}

void Evaluator::eval_NOT (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	ERROR_ON(!Any::isOfType<Array>(tmp),
			"Unary '!' only works for array, but " WORD " found", Any::getType(tmp)); // FIXME
	tmp = static_cast<Array *>(tmp)->neg();
	stack->anyStack.push(tmp, true);
}

uint64_t Evaluator::eval_STARTFOR (Any ** p1, Any ** val, uint64_t addr){
	R_VAR(Symbol*, sym);
	R_VAR(Array*, array);
	R_VAL(Any*, tmp, *val);
	int res;

	debugTraceFunction();

	ERROR_ON(!Any::isOfType<Symbol>(tmp),				// FIXME this must be checked by the bcode verifier
			"For loop need symbol as control var.");// no need to do it on run time
	sym = static_cast<Symbol*>(tmp);

	tmp = stack->anyStack.peek();
	ERROR_ON(!Any::isOfType<Array>(tmp),
			"For loop value must be an array.");
	array = static_cast<Array*>(tmp);

	if(array->length == 0){
		tmp = ConstPool::Null;		// that's for this **** create var
		stack->anyStack.push(tmp);// We don't mind what we are pushing
		stack->intStack.push(0);	// But we have to push
		res = 1; // Direct jump after the end to avoid useless poping
	} else {
		int idx = 0;
		stack->anyStack.push(tmp); // FIXME Do we need a true copy ?
		stack->intStack.push(idx);
		tmp = array->newInstanceWith(1, idx);
		res = 0; // Goto next instruction
	}
	envInfo->writeAt((int64_t) module->pic[pc - 4], sym, tmp); // This line is out of the 'if' only to mimic R ***** behaviour.
	return res;
}

uint64_t Evaluator::eval_STEPFOR (uint64_t p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.peek();
	int idx_val = stack->intStack.peek() + 1;
	if(idx_val < static_cast<Array*>(tmp)->length){ // TODO put in stack this max len ?
		stack->intStack.set(0, idx_val); // Set next index
		printf("**************** %d\n", (int64_t) module->pic[cs[p1 - 2]]);
		envInfo->writeAt(// It's a bit stupid since we know that it's a set
				(int64_t) module->pic[cs[p1 - 2]],
				static_cast<Symbol*>((*cpool)[cs[p1 - 2]]),
				static_cast<Array*>(tmp)->newInstanceWith(1, idx_val));
		return 1;
	} else
		return 0;
}

void Evaluator::eval_ENDFOR (){
	debugTraceFunction();
	stack->intStack.pop();
	stack->anyStack.set(1, ConstPool::Null);
}

void Evaluator::eval_ADD (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	jitddo(printf("[jit-debug] Adding :\n[jit-debug]\t");
			fflush(NULL);
			stack->anyStack.peek()->print();
			fflush(NULL);
			printf("\n[jit-debug]\t");
			tmp->print();
			fflush(NULL);
			PrintNewLine();)
	tmp = R::add(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
	jitddo(printf("[jit-debug] Result ->");fflush(NULL);tmp->print();fflush(NULL);PrintNewLine();)
}

void Evaluator::eval_SUB (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::sub(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_MUL (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::mult(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_EXPT (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::pow(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_DIV (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::div(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_EQ (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::eq(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_NE (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::ne(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_GT (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::gt(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_GE (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::ge(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_LT (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::lt(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_LE (Any ** p1){
	R_VAR(Any *, tmp);
	debugTraceFunction();
	tmp = stack->anyStack.pop();
	tmp = R::le(stack->anyStack.pop(), tmp);
	stack->anyStack.push(tmp, true); /* no need to check the stack there are at least two rooms */
}

void Evaluator::eval_AND (Any ** p1){
	R_VAR(Logical *, l);
	R_VAR(Logical *, r);
	R_VAR(Logical *, res);
	int m, M, rl, ll, l_is_grt = 0;
	debugTraceFunction();
	r = stack->anyStack.pop<Logical>(); // FIXME deal here with more than logical
	l = stack->anyStack.pop<Logical>(); // FIXME deal here with more than logical
	ERROR_ON(!Any::isOfType<Array>(l) || !Any::isOfType<Array>(r),
		"AND is only valid for arrays");
	ll = l->length;
	rl = r->length;
	m = min<int>(ll, rl);
	M = max<int>(ll, rl);
	if(M == ll)  l_is_grt = 1;
	if(!(M % m))
		warning("longer object length is not a multiple of shorter object length");
	res = Logical::doNew(M);
	if(l_is_grt)
		for(int i = 0, j = 0; i < M; j = ((++i) == m) ? 0 : (j+1))  // TODO everything here is inefficient, must do a dispatch to avoid many polymorphics operations
			res->setElement(R_AND(r->getElement(i), l->getElement(j)), i);
	else
		for(int i = 0, j = 0; i < M; j = ((++i) == m) ? 0 : (j+1))  // TODO everything here is inefficient, must do a dispatch to avoid many polymorphics operations
			res->setElement(R_AND(r->getElement(i), l->getElement(j)), i);
}

void Evaluator::eval_OR (Any ** p1){ debugTraceFunction(); nyi_fatal(); }

void Evaluator::eval_SWAP (){
	debugTraceFunction();
	stack->anyStack.swap();
}

void Evaluator::eval_BCMISMATCH(){
	FATAL("BC Mismatch"); // FIXME
}

#define EVAL_PREDICATE(__name, __pred)\
void Evaluator::eval_ ## __name (){   \
	R_VAR(Any *, tmp);                  \
	tmp = stack->anyStack.pop();        \
	stack->anyStack.push((__pred(tmp)) ?\
			ConstPool::True : ConstPool::False,\
			true);\
}

#define ISNULL(__val) ((__val) == ConstPool::Null)
EVAL_PREDICATE(ISNULL, ISNULL)
EVAL_PREDICATE(ISLOGICAL, Any::isOfType<Logical>);
EVAL_PREDICATE(ISINTEGER, Any::isOfType<Int>);
EVAL_PREDICATE(ISDOUBLE, Any::isOfType<Double>);
EVAL_PREDICATE(ISCHARACTER, Any::isOfType<String>);
EVAL_PREDICATE(ISSYMBOL, Any::isOfType<Symbol>);
EVAL_PREDICATE(ISNUMERIC, Any::isOfType<Number>);

void Evaluator::eval_ISCOMPLEX (){ debugTraceFunction();nyi_fatal(); }
void Evaluator::eval_ISOBJECT (){ debugTraceFunction();nyi_fatal(); }

void Evaluator::eval_UPLUS (Any ** p1){
	R_VAL(Any*, tmp, stack->anyStack.peek());
	debugTraceFunction();
	ERROR_ON(!Any::isOfType<Number>(tmp), "non-numeric argument to unary operator");
}

void Evaluator::eval_STARTLOOPCNTXT (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_ENDLOOPCNTXT (){ nyi_fatal(); }
void Evaluator::eval_DOLOOPNEXT (){ nyi_fatal(); }
void Evaluator::eval_DOLOOPBREAK (){ nyi_fatal(); }
void Evaluator::eval_SETLOOPVAL (){ nyi_fatal(); }
void Evaluator::eval_DDVAL (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_GETFUN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_GETGLOBFUN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_GETSYMFUN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_GETBUILTIN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_GETINTLBUILTIN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_DOMISSING (){ nyi_fatal(); }
void Evaluator::eval_SETTAG (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_DODOTS (){ nyi_fatal(); }
void Evaluator::eval_SQRT (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_EXP (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_DOTSERR (){ nyi_fatal(); }
void Evaluator::eval_STARTASSIGN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_ENDASSIGN (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_STARTC (Any ** p1, uint64_t p2){ nyi_fatal(); }
void Evaluator::eval_DFLTC (){ nyi_fatal(); }
void Evaluator::eval_NVECELT (){ nyi_fatal(); }
void Evaluator::eval_NMATELT (){ nyi_fatal(); }
void Evaluator::eval_SETNVECELT (){ nyi_fatal(); }
void Evaluator::eval_SETNMATELT (){ nyi_fatal(); }
void Evaluator::eval_DDVAL_MISSOK (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_STARTASSIGN2 (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_ENDASSIGN2 (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_SETTER_CALL (Any ** p1, Any ** p2){ nyi_fatal(); }
void Evaluator::eval_GETTER_CALL (Any ** p1){ nyi_fatal(); }
void Evaluator::eval_DUP2ND (){ nyi_fatal(); }
void Evaluator::eval_SWITCH (Any ** p1, Any ** p2, void * p3, void * p4){ nyi_fatal(); }

// Will never be implemented
uint64_t Evaluator::eval_AND1ST (Any ** p1, uint64_t p2){ nyi_fatal(); return 0; }
void Evaluator::eval_AND2ND (Any ** p1){ nyi_fatal(); }
uint64_t Evaluator::eval_OR1ST (Any ** p1, uint64_t p2){ nyi_fatal(); return 0; }
void Evaluator::eval_OR2ND (Any ** p1){ nyi_fatal(); }

namespace R{
	int match_pattern(char *input, pattern_t *pattern);
};

struct matched_params {
	uint32_t	idx;
	uint32_t	data;
	Any*			dots;
};

void Evaluator::matchParams(uint32_t stack_args, cpool_int *kw_descr, FunInfo *fun, EnvInfo *env, int32_t* result){
	R_PARAM(env);
	R_VAR(Vector*, dotsValues);
	R_VAL(Bindings*, bindings, fun->bindings);
	pattern_t *params = fun->dstruct; // For partial matching

	uint32_t kw_args = kw_descr->size;
	uint32_t frame_ptr = stack_args - 1;
	uint32_t nbParams = bindings->size;

	uint32_t nbMatched = 0;
	uint32_t nbDotsArgs = 0;
	uint32_t dotPos = nbParams;

	uint32_t max = nbParams > stack_args ? nbParams : stack_args; // FIXME remove this test
	matched_params *matched = (matched_params*)alloca(sizeof(*matched)*max); // FIXME split matched_params in 2 (again)

	for(int i = 0; i < nbParams; i++){ // FIXME remove this block
		if(bindings->key(i) == SymbolTable::threeDots){
			dotPos = i;
			break;
		}
	}

	if(kw_args){ // First, match keywords
		Assert(kw_descr->names > 0,
				"Params need names (internal error)");
		Assert((module->cpool_orig + kw_descr->names)->type == CPOOL_STRSXP,
				"Keyword description must be a StringSXP");
		int *names = (module->cpool_orig + kw_descr->names)->data.pe_vector.values;

		for(uint32_t i = 0; i < kw_args; i++){
			Symbol *kw = static_cast<Symbol*>((*cpool)[names[i]]);
			int callsite_pos = kw_descr->values[i] - 1; // FIXME remove this constant (comes from base 1 indexing of R bc compiler)
			Assert(Any::isOfType<Symbol>(kw),
					"Keyword of type Symbol expected but type is " WORD, kw->getType(kw));
#if R_EXACT_KEYWORDS
			// This code was while using exact matching
			int64_t found_pos = bindings->resolve(kw);
#else
			// This code is experimental and used for partial matching
			int64_t found_pos = match_pattern(kw->text, params);
#endif
			if(found_pos < 0){ // Keyword is not found
				ERROR_ON(!fun->hasDot, "Unknown keyword '%s' in frame", kw->text); // TODO better behaviour than aborting
			} else { // Keyword found
				// Note: we have to go throught bindings->key 'cause of partial names
				env->writeAt(found_pos, bindings->key(found_pos), stack->anyStack.peek(frame_ptr - callsite_pos));
				// Strange indexing, see draft for it
				matched[found_pos].idx = i;
				matched[i].data = callsite_pos;
				result[callsite_pos] = found_pos;
				nbMatched ++;
			}
		}
	}

	// Then match by position
	// i is for idx, j is for args
	uint32_t i = 0, j = 0;
	while(nbMatched < stack_args) { // now match the others
		uint32_t res = result[i];
		uint32_t idx = (res > nbParams) ? nbMatched : matched[res].idx; // This test is here 'cause nothing is allocated // FIXME remove and/or merge

//  		printf("=---- %2d -- %2d -- %2d -- %2d -----=\n", i, j , idx, res);
//   		for(int id = 0; id < max; id ++)
//   			printf("%d: %10d %10d %10d\n", id, matched[id].idx, matched[id].data, result[id]);
 
 		//printf("(T) --- %d < %d && %d == %d \n", idx, nbMatched, matched[idx].data, i); // Carefull this might segfault
		
			// continue; // just to be explicit
		if(!((idx < nbMatched) && (matched[idx].data == i))){ // this is always false is the previous is true 
				while(matched[j].idx < nbMatched && result[matched[matched[j].idx].data] == j) // FIXME optimize
					j++;
				if(j < dotPos){ // param by position
// 					printf("(2) --- %d  -- %d -- %d \n", j, nbMatched, i);
					env->writeAt(j, bindings->key(j), stack->anyStack.peek(frame_ptr));
					// j ?=? frame_ptr - nbParams
					matched[j].idx = nbMatched;
					matched[nbMatched].data = i;
					result[i] = j;
					j ++; nbMatched ++;
				} else if(fun->hasDot){ // It's unknown, it's a 3 dots
// 					printf("(3) --- %d  -- %d -- %d \n", j, nbMatched, i);
					do { // now match the ``...''
						result[i] = -1;
						matched[nbDotsArgs ++].dots = stack->anyStack.peek(frame_ptr --);
// 						printf("%d < %d\n", nbMatched, stack_args);
						if(!(++ nbMatched < stack_args))
							break; // We gobble everything so we can safely exit
						i ++;
						while(result[i] < nbParams && matched[result[i]].idx < nbMatched && matched[matched[result[i]].idx].data == i) // FIXME optimize
						{ frame_ptr--; i ++;}
					} while(1);
				} else
					FATAL("More arguments than expected");
		}
		else 
				;//	printf("(1) --- %d  -- %d -- %d \n", j, nbMatched, i); // REMOVEME
		++i; frame_ptr --;
	}

	if(nbDotsArgs){ // FIXME Rewrite
		nyi_fatal();
		dotsValues = Vector::doNew(nbDotsArgs);
		//memcpy(dotsValues->content, matched->dots, sizeof(Any*)*nbDotsArgs);
		for(int id = 0 ; id < nbDotsArgs; id++)
			dotsValues->content[id] = matched[id].dots;
		env->createLocalVar(SymbolTable::threeDots, dotsValues);
		result[stack_args] = nbDotsArgs;
	}

// 	for(int i = 0; i < nbParams; i ++)
// 		printf("%d --> %d\n", i, result[i]);
// 	printf("\\---------------------/\n");
//Debugger::getDebugger(this);
}

void Evaluator::fastMatchParams(uint32_t nbArgs, FunInfo *fun, EnvInfo *env, void *matchedArgs){
	R_PARAM(env);
	R_VAR(Vector *,dotsValues);
	R_VAL(Bindings*, bindings, fun->bindings);
	int32_t *matched = (int32_t*)matchedArgs;
	int i = 0;
	int dotSize;

	if((dotSize = matched[nbArgs])){
		int dotPos = 0, pos;
		dotsValues = Vector::doNew(dotSize);

		while(nbArgs--)
			if((pos = matched[i++]) >= 0)
				env->createLocalVar(bindings->key(pos), stack->anyStack.peek(nbArgs));
			else
				dotsValues->content[dotPos++] = stack->anyStack.peek(nbArgs);

		env->createLocalVar(SymbolTable::threeDots, dotsValues);
	} else
		while(nbArgs --)
			env->createLocalVar(bindings->key(matched[i++]), stack->anyStack.peek(nbArgs));
	//Debugger::getDebugger(this);
}

void Evaluator::jit_matchParams(uint32_t stack_args, cpool_int *kw_descr, FunInfo *fun, EnvInfo *env){
	/*R_VAR(Vector*, dotsValues);
	R_VAL(Bindings*, bindings, fun->bindings);

	pattern_t *params = fun->dstruct; // For partial matching
  uint32_t kw_args = kw_descr->size;
  uint32_t frame_ptr = stack_args-1;
  uint32_t nbParams = bindings->size;

  uint32_t matched = 0;
	uint32_t nbDotsArgs = 0;
  uint32_t *matched_idx = (uint32_t*)alloca(sizeof(uint32_t)*nbParams);
  uint32_t *matched_data = (uint32_t*)alloca(sizeof(uint32_t)*nbParams);
  Any** dotsArgs = (Any**)alloca(sizeof(Any*)*nbParams);

  if(kw_args){ // First, match keywords
    Assert(kw_descr->names > 0,
				"Params need names (internal error)");
    Assert((module->cpool_orig + kw_descr->names)->type == CPOOL_STRSXP,
				"Keyword description must be a StringSXP");
    int *names = (module->cpool_orig + kw_descr->names)->data.pe_vector.values;

    for(uint32_t i = 0; i < kw_args; i++){
      Symbol *kw = (Symbol*)(*cpool)[names[i]];
      Assert(Any::isOfType<Symbol>(kw),
          "Keyword of type Symbol expected but type is " WORD, kw->getType(kw));
#if 0
			// This code was while using exact matching
      int64_t found_pos = bindings->resolve(kw);
#else
			// This code is experimental and used for partial matching
      int64_t found_pos = match_pattern(kw->text, params);
#endif			
			if(found_pos < 0){ // Keyword is not found
				rerror_on(!fun->hasDot, "Unknown keyword %s in frame", kw->text); // TODO better behaviour than aborting
				// it's fine if we are a variadic function
				// TODO assign the name
				rprintf("%s key is a ...", kw->text);
				dotsArgs[nbDotsArgs ++] = stack->anyStack.JITPeek(frame_ptr - kw_descr->values[i] + 1);
			} else { // Keyword found
				env->createLocalVar(kw, stack->anyStack.JITPeek(frame_ptr - kw_descr->values[i] + 1)); // FIXME remove this constant (comes from base 1 indexing of R bc compiler)
				DUMMY_ADD(matched, found_pos, i);
			}
    }
    matched += kw_args;
  }

	// Then match by position
  for(uint32_t i = 0, idx = matched_idx[i];
      matched < stack_args; idx = matched_idx[++i]){ // now match the others

    rerror_on(((idx < matched) && (matched_data[idx] == i)),
				"Something wrong in matchParams !! %d, %d", idx, matched);

		if(i < nbParams){ // param by position
			env->createLocalVar(bindings->key(i), stack->anyStack.JITPeek(frame_ptr));
			DUMMY_ADD(matched, i, matched);
			frame_ptr --; matched ++;
		} else if(fun->hasDot){ // It's unknown, it's a 3 dots
			dotsArgs[nbDotsArgs ++] = stack->anyStack.JITPeek(frame_ptr);
			frame_ptr --; matched ++;
		} else
			rfatal("More arguments than expected");
  }

	if(nbDotsArgs){
		dotsValues = Vector::doNew(nbDotsArgs);
		memcpy(dotsValues->content, dotsArgs, sizeof(Any*)*nbDotsArgs);
		env->createLocalVar(SymbolTable::threeDots, dotsValues);
	}*/
}
